package com.njlime.cms.sdk.letv;

import org.apache.http.HttpResponse;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Server information.Before using,you should initialize.
 *
 * @author liufengyu
 */
public class LetvApiClient implements Cloneable {

    Logger logger = LoggerFactory.getLogger(LetvApiClient.class);

    //	private String host = "openapi.letvcloud.com";
    private int httpPort = 80;
    private int httpsPort = 443;
    //	private String context = "";
//	private String httpHost;
//	private String httpsHost;
    private String userid;
    private String secret;

    private String apiUrl;
    private static final LetvApiClient instance = new LetvApiClient();

    private RestTemplate restTemplate;

    private LetvApiClient() {
    }

    public LetvApiClient clone() {
        LetvApiClient openapi = new LetvApiClient();
        openapi.setUserid(userid);
        openapi.setSecret(secret);
        try {
            openapi.initialize();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return openapi;
    }

    public static LetvApiClient getInstance() {
        return instance;
    }

    /**
     * 初始化
     *
     * @throws Exception Exception
     */
    public void initialize() throws Exception {
        if (restTemplate != null) {
            return;
        }
        if (userid == null || secret == null || apiUrl == null) {
            throw new NullPointerException("please initialize userid,secret,apiUrl in LetvApiClient first.");
        }

        if (restTemplate == null) {
            TrustManager easyTrustManager = new EasyX509TrustManager();
            X509HostnameVerifier easyHostnameVerifier = new EasyX509HostnameVerifier();

            SSLContext sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, new TrustManager[]{easyTrustManager}, null);

            SSLSocketFactory sf = new SSLSocketFactory(sslcontext, easyHostnameVerifier);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", this.httpPort, PlainSocketFactory.getSocketFactory()));
            schemeRegistry.register(new Scheme("https", this.httpsPort, sf));

            PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
            cm.setMaxTotal(200);
            cm.setDefaultMaxPerRoute(20);
            restTemplate = new RestTemplate(cm);
        }
    }

    public HttpResponse executeGet(String method, String ver, Map<String, String> params) throws IOException {
        return this.executeGet(method, ver, params, null);
    }

    public HttpResponse executeGet(String method, String ver, Map<String, String> params, Map<String, String> headers)
            throws IOException {
        Map<String, String> map = new OrderRetainingMap();
        map.put("method", method);
        map.put("ver", ver);
        map.put("userid", this.getUserid());
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        if (params != null) {
//            map.putAll(params);
            for (String key : params.keySet()) {
                map.put(key, params.get(key));
            }
        }
        String sign = LetvApiUtil.digest(map, this.getSecret());
        map.put("sign", sign);

        return restTemplate.getForObject(apiUrl, map, headers);
    }

    public HttpResponse executePost(String method, String ver, Map<String, String> params) throws IOException {
        return this.executePost(method, ver, params, null);
    }

    public HttpResponse executePost(String method, String ver, Map<String, String> params, Map<String, String> headers)
            throws IOException {
        Map<String, String> map = new OrderRetainingMap();
        map.put("method", method);
        map.put("ver", ver);
        map.put("userid", this.getUserid());
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));

        if (params != null) {
//            map.putAll(params);
            for (String key : params.keySet()) {
                map.put(key, params.get(key));
            }


        }
        String sign = LetvApiUtil.digest(map, this.getSecret());
        map.put("sign", sign);
        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

        return restTemplate.postForObject(apiUrl, map, headers);
    }

    /**
     * 传递图片，文件等上传
     *
     * @param params
     * @return
     */
    public HttpResponse postMultipartForObject(String method, String ver, Map<String, String> params, File file) throws IOException {
        Map<String, String> map = new OrderRetainingMap();
        map.put("method", method);
        map.put("ver", ver);
        map.put("userid", this.getUserid());
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        if (params != null) {
//            map.putAll(params);
            for (String key : params.keySet()) {
                map.put(key, params.get(key));
            }
        }
        String sign = LetvApiUtil.digest(map, this.getSecret());
        map.put("sign", sign);

        return restTemplate.postMultipartForObject(apiUrl, map, file);
    }


    public HttpResponse executeDelete(String method, String ver, Map<String, String> params) throws IOException {
        return executeDelete(method, ver, params, null);
    }

    public HttpResponse executeDelete(String method, String ver, Map<String, String> params, Map<String, String> headers)
            throws IOException {
        Map<String, String> map = new OrderRetainingMap();
        map.put("method", method);
        map.put("ver", ver);
        map.put("userid", this.getUserid());
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        if (params != null) {
//            map.putAll(params);
            for (String key : params.keySet()) {
                map.put(key, params.get(key));
            }
        }

        String sign = LetvApiUtil.digest(map, this.getSecret());
        map.put("sign", sign);

        return restTemplate.deleteForObject(apiUrl, map, headers);
    }

//
//	/**
//	 * 带有accessToken的http请求
//	 * 
//	 * @param url
//	 * @param params
//	 * @return
//	 * @throws Exception
//	 * 
//	 * @author liufengyu
//	 * @date 2012-4-23
//	 */
//	public HttpResponse postMultipartWithAccessToken(String url, Map<String, String> params,
//	        Map<String, byte[]> multipart, String accessToken) throws Exception {
//		Map<String, String> map = new HashMap<String, String>();
//		map.put("access_token", accessToken);
//		if (params != null) {
//			map.putAll(params);
//		}
//
//		map.put("call_id", this.getCallId());
//		map.put("timestamp", this.getTimestamp());
//		String digest = ParameterUtil.digest(map, this.secret);
//		map.put("digest", digest);
//		return restTemplate.postMultipartForObject(url, map, multipart);
//	}

    /**
     * @return the userid
     */
    public String getUserid() {
        return userid;
    }

    /**
     * @param userid the userid to set
     */
    public void setUserid(String userid) {
        this.userid = userid;
    }

    /**
     * @return the secret
     */
    public String getSecret() {
        return secret;
    }

    /**
     * @param secret the secret to set
     */
    public void setSecret(String secret) {
        this.secret = secret;
    }

    public String getApiUrl() {
        return apiUrl;
    }

    public void setApiUrl(String apiUrl) {
        this.apiUrl = apiUrl;
    }

    /**
     * @return the httpPort
     */
    public int getHttpPort() {
        return httpPort;
    }

    /**
     * @param httpPort the httpPort to set
     */
    public void setHttpPort(int httpPort) {
        this.httpPort = httpPort;
    }

    /**
     * @return the httpsPort
     */
    public int getHttpsPort() {
        return httpsPort;
    }

    /**
     * @param httpsPort the httpsPort to set
     */
    public void setHttpsPort(int httpsPort) {
        this.httpsPort = httpsPort;
    }

}